<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>css3 transform 实现元素的拖动</title>
  </head>
  <style>
    html,
    body {
      padding: 0;
      margin: 0;
      height: 100%;
    }

    .container {
      position: relative;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 500px;
      height: 400px;
      box-shadow: 0 0 8px 0 #353535;
    }

    .drop_box {
      width: 100px;
      height: 100px;
      border-radius: 100%;
      background-color: skyblue;
      cursor: move;
      transform: translate3d(0px, 0px, 0px);
    }
  </style>
  <body>
    <div class="container">
      <div class="drop_box"></div>
    </div>
    <script>
      const $ = (selector) => {
        return document.querySelector(selector);
      };
      const container = $(".container");
      const drop_box = $(".drop_box");

      start(container, drop_box);

      function start(container, move_element) {
        const getTargetElement = (el) => {
          return el.getBoundingClientRect();
        };

        const getMousePos = (el, ev) => {
          const target = getTargetElement(el);
          return {
            x: ev.clientX - target.x,
            y: ev.clientY - target.y,
          };
        };

        const updatePos = (el, x, y) => {
          // el.style.transform = `translate3d(${x}px, ${y}px, 0px)`;
          el.style.cssText = `transform: translate3d(${x}px, ${y}px, 0px)`;
        };

        let isDown = false;

        // 记录按下的位置
        let initPos = { x: 0, y: 0 };

        // 设置初始位置
        updatePos(move_element, initPos.x, initPos.y);

        let b = getTargetElement(move_element);
        let c = getTargetElement(container);
        // 可拖动的范围
        let _h = c.height - b.height;
        let _w = c.width - b.width;

        function dragMove(ev) {
          ev.preventDefault();
          if (!isDown) return;

          // 元素在容器上面拖动
          const p = getMousePos(this, ev);
          // 控制拖动范围,可以判断上下左右边界
          let x = Math.min(Math.max(0, p.x - initPos.x), _w);
          let y = Math.min(Math.max(0, p.y - initPos.y), _h);

          updatePos(move_element, x, y);
        }

        function dragEnd(ev) {
          ev.preventDefault();
          isDown = false;

          container.removeEventListener("mousemove", dragMove);
          container.removeEventListener("mouseup", dragEnd);
          container.removeEventListener("mouseleave", dragEnd);
        }

        function dragBegin(ev) {
          ev.preventDefault();
          isDown = true;

          // 记录鼠标按下的位置
          initPos = getMousePos(this, ev);

          container.addEventListener("mousemove", dragMove);
          container.addEventListener("mouseup", dragEnd);
          container.addEventListener("mouseleave", dragEnd);
        }

        move_element.addEventListener("mousedown", dragBegin);
      }
    </script>
  </body>
</html>
